#pragma once

#include <mutex>
#include "lwip/tcp.h"
#include "lwip/priv/tcpip_priv.h"
#include "freertos/FreeRTOS.h"
#include "freertos/queue.h"

extern uint32_t get_ms_since_start();
extern bool  is_timeout(uint32_t start_time, uint32_t timeout);
extern err_t close_tcp(tcp_pcb* pcb);
extern void  abort_tcp(tcp_pcb* pcb);

class Async;
class AsyncClient;
class AsyncServer;

/// @brief 定义LWIP事件类型
using lwip_event_type_t = enum lwip_event_type_type {
    LWIP_TCP_SENT,          // 数据成功发送至网络事件
    LWIP_TCP_RECV,          // 收到数据包事件
    LWIP_TCP_FIN,           // 对方主动关闭事件
    LWIP_TCP_ERROR,         // 协议栈错误事件
    LWIP_TCP_POLL,          // 轮询事件
    LWIP_TCP_ACCEPT,        // 新连接请求事件
    LWIP_TCP_CONNECTED,     // 连接建立成功事件
    LWIP_TCP_DNS            // DNS解析事件
};

/// @brief 定义LWIP事件的组成
using lwip_event_t = struct lwip_event_type {
    void*   arg;
    lwip_event_type_t   type;
    union {
        AsyncClient*    accep_client;
        err_t           err_err;
        ip_addr_t       dns_addr;
        struct {
            tcp_pcb*    recv_pcb;
            pbuf*       recv_pb;
            err_t       recv_err;
        };
        struct {
            tcp_pcb*    fin_pcb;
            err_t       fin_err;
        };
        struct {
            tcp_pcb*    sent_pcb;
            uint16_t    sent_len;
        };
        struct {
            tcp_pcb*    poll_pcb;
        };
        struct {
            tcp_pcb*    conn_pcb;
            err_t       conn_err;
        };

    };
};

/// @brief 定义在LWIP 线程中执行的函数的参数
using tcp_api_call_t = struct tcp_api_call_type {
    tcpip_api_call_data call;
    struct {
        tcp_pcb*    pcb;
        union {
            uint8_t     listen_backlog;
            uint16_t    recv_len;
            struct {
                ip_addr_t*  bind_addr;
                uint16_t    bind_port;
            };
            struct {
                ip_addr_t*  conn_addr;
                uint16_t    conn_port;
                tcp_connected_fn    conn_fn;
            };
            struct {
                const void* write_data;
                uint16_t    write_len;
                u8_t        write_apiflag;
            };
        };
    };
};

class Async {
public:
    static Async* GetInstance()
    {
        static Async* instance = nullptr;
        if (instance == nullptr) {
            instance = new Async();
        }
        return instance;
    }
    bool send_event_to_queue(lwip_event_t* e);
    void handle_async_event(lwip_event_t* e);
    void push_event_to_pool(lwip_event_t* e);
    lwip_event_t*   get_event_from_pool();

private:
    Async();
    ~Async();
    bool    create_event_handle_task();
    uint8_t init_event_pool();
    void    delete_event_pool();

    std::mutex      m_queue_mutex;
    QueueHandle_t   m_async_queue;
    std::mutex      m_event_mutex;
    QueueHandle_t   m_event_pool;
    TaskHandle_t    m_async_task;
};